import CryptoJS from "crypto-js";
import {IAesKey} from "@/iwb/IUser";
import {TimeUtils} from "@/utils/TimeUtils";
import {useEncryptStore} from "@/store/encrypt";
import {useUserStore} from "@/store/user";
import {RsaUtils} from "@/utils/RsaUtils";
import {Utils} from "@/utils/utils";

/**
 * AES加密
 */
export class AesUtils {

    private static aesKey = {} as IAesKey;
    static generateKey(num: number) {
        let library = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        let key = '';
        for (let i=0; i<num; ++i) {
            let randomPoz = Math.floor(Math.random() * library.length);
            key += library.substring(randomPoz, randomPoz+1);
        }
        return key;
    }
    static async createAesKey() {
        let aesKey = this.aesKey;
        /**
         * 获取存储的KEY
         */
        if(!aesKey.encryptKey || TimeUtils.isPastTime((aesKey.expireTime + aesKey.createTime) * 1000)) {
            this.aesKey.encryptKey = this.generateKey(32);
            this.aesKey.iv = this.generateKey(16);
            this.aesKey.version = aesKey.version ? aesKey.version+1 : 0;
            this.aesKey.expireTime = 3000;
            this.aesKey.createTime = new Date().getTime() / 1000;
            const userStore = useUserStore();
            if (userStore.token) {
                /**
                 * 系统已经登录，但是页面刷新导致数据丢失
                 * 所以才重新创建同步KEY
                 */
                const encryptStore = useEncryptStore();
                let syncKey = {} as IAesKey;
                RsaUtils.setPublicKey(userStore.publicKey);
                // @ts-ignore
                syncKey.encryptKey = RsaUtils.RsaEncrypt(this.aesKey.encryptKey);
                // @ts-ignore
                syncKey.iv = RsaUtils.RsaEncrypt(this.aesKey.iv);
                syncKey.version = this.aesKey.version;
                syncKey.expireTime = this.aesKey.expireTime;
                syncKey.createTime = this.aesKey.createTime;
                await encryptStore.syncAesKey(syncKey);
            }
        }
        return this.aesKey;
    }
    /**
     * aes cbc解密方法、需要iv偏移量
     * @param word
     */
    static async AesDecrypt(word: string) {
        if (!Utils.enableEncrypt) return word;
        let aesKey = await this.createAesKey();
        let encryptedHexStr = CryptoJS.enc.Hex.parse(word);
        let srcs = CryptoJS.enc.Base64.stringify(encryptedHexStr);
        const key = CryptoJS.enc.Utf8.parse(aesKey.encryptKey);
        const iv = CryptoJS.enc.Utf8.parse(aesKey.iv);
        let decrypt = CryptoJS.AES.decrypt(srcs, key, {
            iv: iv,
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.Pkcs7
        });
        let decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
        return decryptedStr.toString();
    }
    /**
     * aes cbc加密方法、需要iv偏移量
     * @param word
     */
    static async AesEncrypt(word: string) {
        if (!Utils.enableEncrypt) return word;
        let aesKey = await this.createAesKey();
        let srcs = CryptoJS.enc.Utf8.parse(word);
        const key = CryptoJS.enc.Utf8.parse(aesKey.encryptKey);
        const iv = CryptoJS.enc.Utf8.parse(aesKey.iv);
        let encrypted = CryptoJS.AES.encrypt(srcs, key, {
            iv: iv,
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.Pkcs7
        });
        return encrypted.ciphertext.toString().toUpperCase();
    }
    /**
     * base64 加密方法
     * @param word
     */
    static Base64Encode(word: string) {
        let str = CryptoJS.enc.Utf8.parse(word);
        let base64 = CryptoJS.enc.Base64.stringify(str);
        return base64;
    }
    /**
     * base64 解密方法
     * @param word
     */
    static Base64Decode(word: string) {
        let words = CryptoJS.enc.Base64.parse(word);
        return words.toString(CryptoJS.enc.Utf8);
    }
    /**
     * aes ecb解密方法
     * @param word
     */
    static async AesDecryptECB(word: string) {
        if (!Utils.enableEncrypt) return word;
        let aesKey = await this.createAesKey();
        let encryptedHexStr = CryptoJS.enc.Hex.parse(word);
        let srcs = CryptoJS.enc.Base64.stringify(encryptedHexStr);
        const key = CryptoJS.enc.Utf8.parse(aesKey.encryptKey);
        let decrypt = CryptoJS.AES.decrypt(srcs, key, {
            mode: CryptoJS.mode.ECB,
            padding: CryptoJS.pad.Pkcs7
        });
        let decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
        return decryptedStr.toString();
    }
    /**
     * aes ecb加密方法
     * @param word
     */
    static async AesEncryptECB(word: string) {
        if (!Utils.enableEncrypt) return word;
        let aesKey = await this.createAesKey();
        let srcs = CryptoJS.enc.Utf8.parse(word);
        const key = CryptoJS.enc.Utf8.parse(aesKey.encryptKey);
        let encrypted = CryptoJS.AES.encrypt(srcs, key, {
            mode: CryptoJS.mode.ECB,
            padding: CryptoJS.pad.Pkcs7
        });
        return encrypted.ciphertext.toString().toUpperCase();
    }

    /**
     * sha256加密
     * @param word
     */
    static sha265(word: string): string {
        return CryptoJS.enc.Hex.stringify(CryptoJS.SHA256(word));
    }
}